WebGL not working on android

I have downloaded the https://snack.expo.io/@community/flappy-bird snack and imported it to my project. (I’m using react-navigation’s tabnavigator inside a stacknavigator) The GameKit code is the exact same as in the example, and on iOS it works totally fine. I have also noticed a black bar (about 1px wide) at the leftmost of my view. The score renders fine, and if you click the view it even increments. (Though you still can’t see anything)

Does anyone have a solution to this?

It looks like maybe that thin black bar is the game view, this is probably a style error you can try setting the width in the style prop.

{ width: '100%' }

also if you are resizing the view dynamically, you will need to update the context. This can be done easily with expo-graphics.
Another important thing to note; since that tutorial came out much better libs for 2D games have been released.

Thanks for the quick reply! The only question left is: How exactly can I update the GL context? Is onResize the way to go?

This is what you want: https://github.com/expo/expo-graphics/blob/42d1577bd0420294550052cd7145c82f3fc4a2fd/examples/three/App.js#L61-L66

  onResize = ({ width, height, scale }) => {
    this.camera.aspect = width / height;
    this.camera.updateProjectionMatrix();
    this.renderer.setPixelRatio(scale);
    this.renderer.setSize(width, height);
  };

UPDATE4: Very hacky, but solved.

This is GameScreen.js:

componentDidMount() {
  setTimeout(() => this.setState({ amazingKey: this.state.amazingKey+1 }), 2000);
}
// ..snip..
render() {
    return (
      <View key={this.state.amazingKey} style={StyleSheet.absoluteFill}>
        <SpriteView
          touchDown={() => this.tap()}
          touchMoved={() => {}}
          touchUp={() => {}}
          update={this.updateGame}
          onSetup={this.onSetup}
        />
        {this.renderScore()}
      </View>
    );
}

UPDATE3: Now it’s working, but only when I put the app in the background and bring it back again. (Otherwise I can only see the background image) (Did the GL context initialize improperly?) Do You have a solution for this?

Here’s my updated spriteview:

import ExpoGraphics from 'expo-graphics';
import ExpoTHREE, { THREE } from 'expo-three';
import React from 'react';
import PropTypes from 'prop-types';
import { PanResponder, View, StyleSheet, Platform } from 'react-native';

export default class SpriteView extends React.Component {
  static propTypes = {
    touchDown: PropTypes.func.isRequired,
    touchMoved: PropTypes.func.isRequired,
    touchUp: PropTypes.func.isRequired,
    update: PropTypes.func.isRequired,
    onSetup: PropTypes.func.isRequired
  };

  static defaultProps = {
    touchDown: ({ x, y }) => {},
    touchMoved: ({ x, y }) => {},
    touchUp: ({ x, y }) => {},
    update: currentTime => {},
    onSetup: ({ scene, camera }) => {}
  };

  ///@Evan NOTE: This is lifted from SpriteKit.
  worldSpaceWidth = 750 * 0.333333333;
  worldSpaceHeight = null; //1334

  constructor() {
    super();
    this.setupGestures();
  }

  setupGestures = () => {
    const touchesBegan = ({ nativeEvent }, gestureState) => {
      const { touches } = nativeEvent;
      touches.map(
        ({ target, locationX, locationY, force, identifier, timestamp }) => {
          this.props.touchDown({ x: locationX, y: locationY });
        }
      );
    };

    const touchesMoved = ({ nativeEvent }, gestureState) => {
      const { touches } = nativeEvent;
      touches.map(
        ({ target, locationX, locationY, force, identifier, timestamp }) => {
          this.props.touchMoved({ x: locationX, y: locationY });
        }
      );
    };

    const touchesEnded = ({ nativeEvent }, gestureState) => {
      const { touches } = nativeEvent;
      touches.map(
        ({ target, locationX, locationY, force, identifier, timestamp }) => {
          this.props.touchUp({ x: locationX, y: locationY });
        }
      );
    };

    this.panResponder = PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderGrant: touchesBegan,
      onPanResponderMove: touchesMoved,
      onPanResponderRelease: touchesEnded,
      onPanResponderTerminate: touchesEnded, //cancel
      onShouldBlockNativeResponder: () => false
    });
  };

  render() {
    const { style, ...props } = this.props;
    // Create an `Expo.GLView` covering the whole screen, tell it to call our
    // `_onGLContextCreate` function once it's initialized.
    return (
      <View {...this.panResponder.panHandlers} style={StyleSheet.absoluteFill}>
          <ExpoGraphics.View
            style={StyleSheet.absoluteFill}
            onContextCreate={this._onGLContextCreate}
            onRender={this.onRender}
            onResize={this.onResize}
            onShouldReloadContext={() => { return Platform.OS === 'android'; }}
          />
      </View>
    );
  }

  onRender = delta => {
      this.props.update(delta);
      this.renderer.render(this.scene, this.camera);
  };

  onResize = ({ width, height, scale }) => {
    this.camera.aspect = width / height;
    this.camera.updateProjectionMatrix();
    this.renderer.setPixelRatio(scale);
    this.renderer.setSize(width, height);
  };

  _onGLContextCreate = async ({ gl, canvas, width, height, scale }) => {
    this.renderer = ExpoTHREE.createRenderer({ gl, canvas });
    this.renderer.setPixelRatio(scale);
    this.renderer.setSize(width, height);
    this.renderer.setClearColor(0x000000, 1.0);
    this.scene = new THREE.Scene();

    /// Camera
    this.worldSpaceHeight = height / width * this.worldSpaceWidth;
    this.camera = new THREE.OrthographicCamera(
      this.worldSpaceWidth / -2,
      this.worldSpaceWidth / 2,
      this.worldSpaceHeight / 2,
      this.worldSpaceHeight / -2,
      0,
      1
    );

    this.scene.size = {
      width: this.worldSpaceWidth,
      height: this.worldSpaceHeight
    };
    this.scene.bounds = {
      top: this.camera.top,
      left: this.camera.left,
      bottom: this.camera.bottom,
      right: this.camera.right
    };

    this.camera.position.z = 1;

    await this.props.onSetup({ scene: this.scene, camera: this.camera });
  };
}

OLD CONTENT: Is there any way to do it with Expo.GLView? Or do you have an updated GameKit for expo-graphics as well? The problematic thing that I’m talking about is <SpriteView> here which I’m trying to replace with the new version you’ve provided, but after 2 hours of trying, it still looks like I’m not making any progress :frowning: Sorry to bother you with this, but I really want to get my game to work.

UPDATE: It works, but I can only see the background. Probably the View isn’t updating. Any ideas?
UPDATE2: resolved by wrapping the <ExpoGraphics.View> in a <View>

1 Like

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.