Developing a 1010 game in unity but pieces rearrange themselves sometimes - unity3d
I have a bug in my game that I have spent day and night trying to solve but with no success, so please help if you can. Basicaly I have modified the grid(see picture for clarification) and everything seems to work except when I place the pieces at the corner or the edge pieces it suddenly change shape to fit the grid. I am not that good at describing things so I have taken a few screenshots to illustrate.
When I start the game
When I try to set a piece in the grid but one piece is outside
Piece suddenly change shape, when it shouldn't fit and return to spawnpoint
enter image description here
enter image description here
enter image description here
Here is the code for that is attached to every tetris piece:
public TetrimoPiece[] tetrimoPieces;
public Vector3 originalScale;
public Vector3 originalPos;
public Vector3 originalSpawnPos;
Vector3[] _minAndMaxPoints;
Vector3 _centroid;
public bool isBeingDragged;
public TetrimoSpawnPoint assignedSpawnPoint;
public int originalSortingOrder;
public Color color;
public int SortingOrder {
get {
return tetrimoPieces [0].SortingOrder;
}
set {
foreach (TetrimoPiece piece in tetrimoPieces) {
piece.SortingOrder = value;
}
}
}
void Awake ()
{
tetrimoPieces = GetChildTetrimoPieces ();
originalSortingOrder = SortingOrder;
originalScale = transform.localScale;
originalPos = transform.localPosition;
transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles.x, 0, 0);
if (tetrimoPieces.Count () > 0) {
List<Transform> tetrimoPiecesTransforms = (from tetrimoPiece in tetrimoPieces
select tetrimoPiece.transform).ToList ();
_minAndMaxPoints = GetMinAndMaxPoints (tetrimoPiecesTransforms);
_centroid = FindCentroid (tetrimoPiecesTransforms);
}
SetTetrimoColor ();
}
void Start ()
{
}
public TetrimoPiece[] GetChildTetrimoPieces ()
{
return GetComponentsInChildren<TetrimoPiece> ();
}
public void SetTetrimoColor(){
foreach (TetrimoPiece piece in tetrimoPieces) {
piece.SetColor(color);
}
}
public void GenerateCollider ()
{
List<Transform> tetrimoPiecesTransforms = new List<Transform> ();
foreach (TetrimoPiece piece in tetrimoPieces) {
tetrimoPiecesTransforms.Add (piece.transform);
}
Vector3[] minAndMaxPoints = GetMinAndMaxPoints (tetrimoPiecesTransforms);
Vector3 minPoint = minAndMaxPoints [0];
Vector3 maxPoint = minAndMaxPoints [1];
BoxCollider2D boxColl = gameObject.AddComponent<BoxCollider2D> ();
boxColl.size = new Vector2 ((maxPoint.x - minPoint.x) + tetrimoPieces [0].GetColliderSize ().x, (maxPoint.y - minPoint.y) + tetrimoPieces [0].GetColliderSize ().x);
}
public void MoveTetrimoPiecesToCenter ()
{
List<Transform> tetrimoPiecesTransforms = new List<Transform> ();
foreach (TetrimoPiece piece in tetrimoPieces) {
tetrimoPiecesTransforms.Add (piece.transform);
}
Vector3 centroid = FindCentroid (tetrimoPiecesTransforms);
foreach (Transform child in tetrimoPiecesTransforms) {
child.position -= centroid;
}
}
public Vector3[] GetMinAndMaxPoints (List<Transform> targets)
{
Vector3 minPoint = targets [0].position;
Vector3 maxPoint = targets [0].position;
for (int i = 1; i < targets.Count; i++) {
Vector3 pos = targets [i].position;
if (pos.x < minPoint.x)
minPoint.x = pos.x;
if (pos.x > maxPoint.x)
maxPoint.x = pos.x;
if (pos.y < minPoint.y)
minPoint.y = pos.y;
if (pos.y > maxPoint.y)
maxPoint.y = pos.y;
if (pos.z < minPoint.z)
minPoint.z = pos.z;
if (pos.z > maxPoint.z)
maxPoint.z = pos.z;
}
Vector3[] minAndMaxPoints = new Vector3[]{ minPoint, maxPoint };
return minAndMaxPoints;
}
//CALCULATING THE MEDIAN POINT BETWEEN ALL TETRIMOS
private Vector3 FindCentroid (List< Transform > targets)
{
Vector3 centroid;
Vector3[] minAndMaxPoints = GetMinAndMaxPoints (targets);
Vector3 minPoint = minAndMaxPoints [0];
Vector3 maxPoint = minAndMaxPoints [1];
centroid = minPoint + 0.5f * (maxPoint - minPoint);
return centroid;
}
public void FollowInput ()
{
Vector3 mouseScreenPos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
mouseScreenPos.z = originalPos.z;
transform.position = mouseScreenPos;
}
public bool CanBeReleasedOverGrid ()
{
bool _canBeReleasedOverGrid = true;
List<GridPiece> gridPiecesToFill = new List<GridPiece> ();
foreach (TetrimoPiece piece in tetrimoPieces) {
piece.SetNearestGridPiece ();
gridPiecesToFill.Add (piece.lastNearestGridPiece);
}
foreach (GridPiece gridPiece in gridPiecesToFill) {
if (gridPiece.isFilled || (TutorialManager.instance.isShowingTutorial && !gridPiece.isTutorialFillable)) {
_canBeReleasedOverGrid = false;
break;
}
}
if (TetrimoPiecesShareSameNearestPiece ()) {
_canBeReleasedOverGrid = false;
}
return _canBeReleasedOverGrid;
}
public bool TetrimoPiecesShareSameNearestPiece ()
{
foreach (TetrimoPiece tetrimoPiece in tetrimoPieces) {
foreach (TetrimoPiece brotherPiece in tetrimoPieces) {
bool isBrother = tetrimoPiece != brotherPiece;
if (isBrother) {
if (tetrimoPiece.lastNearestGridPiece == brotherPiece.lastNearestGridPiece) {
return true;
}
}
}
}
return false;
}
public void FillNearestGridPieces ()
{
foreach (TetrimoPiece tetrimoPiece in tetrimoPieces) {
tetrimoPiece.lastNearestGridPiece.SetFilled (true);
tetrimoPiece.lastNearestGridPiece.SetTetrimoThatFillsMe (this);
}
}
public void PlaceOverGrid ()
{
FillNearestGridPieces ();
if (!TutorialManager.instance.isShowingTutorial) {
ScoreHandler.instance.increaseScore (tetrimoPieces.Count ());
}
DestroyImmediate (gameObject);
}
public void MoveToSpawnPosition ()
{
transform.position = originalSpawnPos;
}
public bool CanFitInGrid ()
{
GridPiece[] gridPieces = Grid.instance.gridPieces.ToArray ();
bool canFitInGrid = false;
Vector3 scaleBeforeCheck = transform.localScale;
Vector3 positionBeforeCheck = transform.position;
foreach (GridPiece gridPiece in gridPieces) {
if (gridPiece != null)
{
transform.localScale = originalScale;
transform.position = gridPiece.transform.position;
transform.position += new Vector3(transform.position.x - tetrimoPieces[0].transform.position.x, transform.position.y - tetrimoPieces[0].transform.position.y, transform.position.z);
if (CanBeReleasedOverGrid())
{
canFitInGrid = true;
break;
}
}
}
transform.position = positionBeforeCheck;
transform.localScale = scaleBeforeCheck;
return canFitInGrid;
}
public void ReturnToSpawnPoint (float timeToReachOriginalPos)
{
if (OnReturnToSpawnPointRoutine == null) {
OnReturnToSpawnPointRoutine = DOOnReturnToSpawnPointRoutine (timeToReachOriginalPos);
StartCoroutine (OnReturnToSpawnPointRoutine);
}
}
public IEnumerator OnReturnToSpawnPointRoutine;
public IEnumerator DOOnReturnToSpawnPointRoutine (float timeToReachOriginalPos, bool animated = true)
{
float timeToReachValues = timeToReachOriginalPos;
float t = 0;
float timePassed = 0;
Vector3 startPos = transform.position;
Vector3 startScale = transform.localScale;
Vector3 targetScale = originalScale * TetrimoSpawner.instance.scaleFactorOnSpawnPoint;
if (!animated) {
t = 1;
}
while (t <= 1) {
if (this == null || isBeingDragged) {
yield break;
}
transform.localScale = Vector3.Lerp (startScale, targetScale, t);
transform.position = Vector3.Lerp (startPos, originalSpawnPos, t);
t += Time.deltaTime / timeToReachValues;
timePassed += Time.deltaTime;
if (t >= 1) {
transform.localScale = targetScale;
transform.position = originalSpawnPos;
}
yield return new WaitForEndOfFrame ();
}
OnReturnToSpawnPointRoutine = null;
}
public void OnDrag ()
{
if (OnDragRoutine == null) {
isBeingDragged = true;
OnDragRoutine = DOOnDragRoutine ();
if (OnReturnToSpawnPointRoutine != null) {
StopCoroutine (OnReturnToSpawnPointRoutine);
}
StartCoroutine (OnDragRoutine);
}
}
public void StopDrag ()
{
if (OnDragRoutine != null) {
isBeingDragged = false;
StopCoroutine (OnDragRoutine);
OnDragRoutine = null;
}
}
public IEnumerator OnDragRoutine;
public IEnumerator DOOnDragRoutine ()
{
float timeToReachValues = 0.1f;
float t = 0;
float timePassed = 0;
Vector3 startPos = transform.position;
Vector3 startScale = transform.localScale;
while (t <= 1 && isBeingDragged) {
transform.localScale = Vector3.Lerp (startScale, originalScale, t);
transform.position = Vector3.Lerp (startPos, GetFollowMousePos (), t);
t += Time.deltaTime / timeToReachValues;
timePassed += Time.deltaTime;
if (t >= 1) {
transform.localScale = originalScale;
}
yield return new WaitForEndOfFrame ();
}
while (isBeingDragged) {
transform.position = GetFollowMousePos ();
yield return new WaitForEndOfFrame ();
}
}
public Vector3 GetFollowMousePos ()
{
float distanceBetweenCenterAndTetrimoMinPoint = Mathf.Abs (_centroid.y - _minAndMaxPoints [0].y);
Vector3 worldMousePos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
worldMousePos.z = transform.position.z;
worldMousePos.y += distanceBetweenCenterAndTetrimoMinPoint + 1.15f;
return worldMousePos;
}
public void OnDisable ()
{
Vector3 targetScale = originalScale * TetrimoSpawner.instance.scaleFactorOnSpawnPoint;
transform.position = originalSpawnPos;
transform.localScale = targetScale;
}
and here is the code that is attached to every square pieces that makes up the prefab:
public BoxCollider2D coll;
public GridPiece lastNearestGridPiece;
private SpriteRenderer _spriteRenderer;
public int SortingOrder {
get {
return spriteRenderer.sortingOrder;
}
set {
spriteRenderer.sortingOrder = value;
}
}
public SpriteRenderer spriteRenderer {
get {
if (_spriteRenderer == null) {
_spriteRenderer = GetComponentInChildren<SpriteRenderer> ();
}
return _spriteRenderer;
}
}
void Awake ()
{
coll = GetComponentInChildren<BoxCollider2D> ();
}
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
public Vector2 GetColliderSize ()
{
return coll.bounds.size;
}
public void SetNearestGridPiece ()
{
GridPiece[] gridPieces = Grid.instance.gridPieces.ToArray ();
GridPiece lastNearestGridPieceFound = gridPieces[0];
float lastNearestDistanceFound = Vector3.Distance (gridPieces [0].transform.position, transform.position);
foreach (GridPiece piece in gridPieces) {
float distanceBetweenGridPieceAndThis = Vector3.Distance(piece.transform.position, transform.position);
if (distanceBetweenGridPieceAndThis < lastNearestDistanceFound)
{
lastNearestGridPieceFound = piece;
lastNearestDistanceFound = distanceBetweenGridPieceAndThis;
}
}
lastNearestGridPiece = lastNearestGridPieceFound;
}
public void SetColor (Color color)
{
spriteRenderer.color = color;
}
here is the code for generating grid:
public static Grid instance;
public int rowsCount;
public int columnsCount;
public GridPiecesSet[] rows;
public GridPiecesSet[] columns;
public List<GridPiece> gridPieces;
public float distanceBetweenGroundPieces;
public GridPiece gridPiece;
GridPiecesContainer gridPiecesContainer;
void Awake ()
{
instance = this;
gridPiecesContainer = GetComponentInChildren<GridPiecesContainer> ();
GenerateGrid ();
}
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
//This generates the grid
public void GenerateGrid ()
{
rows = Enumerable.Range (0, columnsCount).Select (i => new GridPiecesSet (columnsCount, GridPiecesSet.Type.row)).ToArray ();
columns = Enumerable.Range (0, rowsCount).Select (i => new GridPiecesSet (rowsCount, GridPiecesSet.Type.column)).ToArray ();
gridPieces = new List<GridPiece> ();
for (int rowsIndex = 0; rowsIndex < rowsCount; rowsIndex++) {
GenerateRow (rowsIndex);
}
gridPiecesContainer.MoveToCenter ();
}
void GenerateRow (int rowsIndex)
{
GridPiece lastSpawnedRowPiece = null;
for (int columnsIndex = 0; columnsIndex < columnsCount; columnsIndex++) {
if (rowsIndex == 0 && columnsIndex == 4 || columnsIndex == 5)
{
GridPiece newGridPiece = Instantiate(gridPiece.gameObject).GetComponent<GridPiece>();
newGridPiece.transform.SetParent(gridPiecesContainer.transform);
Vector3 newPos = newGridPiece.transform.position;
// GENERATING FROM TOP LEFT
newPos.x = (newGridPiece.GetWidth() / 2 + distanceBetweenGroundPieces) * columnsIndex;
newPos.y = (newGridPiece.GetHeight() / 2 + distanceBetweenGroundPieces) * (-rowsIndex);
newGridPiece.transform.position = newPos;
newGridPiece.name = " piece_row_" + rowsIndex + " piece_col_" + columnsIndex;
rows[rowsIndex].gridPieces[columnsIndex] = newGridPiece;
columns[columnsIndex].gridPieces[rowsIndex] = newGridPiece;
gridPieces.Add(newGridPiece);
lastSpawnedRowPiece = newGridPiece.GetComponent<GridPiece>();
}
else if ((columnsIndex >= 3 && columnsIndex <= 6) && rowsIndex == 1)
{
GridPiece newGridPiece = Instantiate(gridPiece.gameObject).GetComponent<GridPiece>();
newGridPiece.transform.SetParent(gridPiecesContainer.transform);
Vector3 newPos = newGridPiece.transform.position;
// GENERATING FROM TOP LEFT
newPos.x = (newGridPiece.GetWidth() / 2 + distanceBetweenGroundPieces) * columnsIndex;
newPos.y = (newGridPiece.GetHeight() / 2 + distanceBetweenGroundPieces) * (-rowsIndex);
newGridPiece.transform.position = newPos;
newGridPiece.name = " piece_row_" + rowsIndex + " piece_col_" + columnsIndex;
rows[rowsIndex].gridPieces[columnsIndex] = newGridPiece;
columns[columnsIndex].gridPieces[rowsIndex] = newGridPiece;
gridPieces.Add(newGridPiece);
lastSpawnedRowPiece = newGridPiece.GetComponent<GridPiece>();
}
else if ((columnsIndex >= 2 && columnsIndex <= 7) && rowsIndex == 2)
{
GridPiece newGridPiece = Instantiate(gridPiece.gameObject).GetComponent<GridPiece>();
newGridPiece.transform.SetParent(gridPiecesContainer.transform);
Vector3 newPos = newGridPiece.transform.position;
// GENERATING FROM TOP LEFT
newPos.x = (newGridPiece.GetWidth() / 2 + distanceBetweenGroundPieces) * columnsIndex;
newPos.y = (newGridPiece.GetHeight() / 2 + distanceBetweenGroundPieces) * (-rowsIndex);
newGridPiece.transform.position = newPos;
newGridPiece.name = " piece_row_" + rowsIndex + " piece_col_" + columnsIndex;
rows[rowsIndex].gridPieces[columnsIndex] = newGridPiece;
columns[columnsIndex].gridPieces[rowsIndex] = newGridPiece;
gridPieces.Add(newGridPiece);
lastSpawnedRowPiece = newGridPiece.GetComponent<GridPiece>();
}
else if ((columnsIndex >= 1 && columnsIndex <= 8) && rowsIndex == 3)
{
GridPiece newGridPiece = Instantiate(gridPiece.gameObject).GetComponent<GridPiece>();
newGridPiece.transform.SetParent(gridPiecesContainer.transform);
Vector3 newPos = newGridPiece.transform.position;
// GENERATING FROM TOP LEFT
newPos.x = (newGridPiece.GetWidth() / 2 + distanceBetweenGroundPieces) * columnsIndex;
newPos.y = (newGridPiece.GetHeight() / 2 + distanceBetweenGroundPieces) * (-rowsIndex);
newGridPiece.transform.position = newPos;
newGridPiece.name = " piece_row_" + rowsIndex + " piece_col_" + columnsIndex;
rows[rowsIndex].gridPieces[columnsIndex] = newGridPiece;
columns[columnsIndex].gridPieces[rowsIndex] = newGridPiece;
gridPieces.Add(newGridPiece);
lastSpawnedRowPiece = newGridPiece.GetComponent<GridPiece>();
}
else if (rowsIndex == 4)
{
GridPiece newGridPiece = Instantiate(gridPiece.gameObject).GetComponent<GridPiece>();
newGridPiece.transform.SetParent(gridPiecesContainer.transform);
Vector3 newPos = newGridPiece.transform.position;
// GENERATING FROM TOP LEFT
newPos.x = (newGridPiece.GetWidth() / 2 + distanceBetweenGroundPieces) * columnsIndex;
newPos.y = (newGridPiece.GetHeight() / 2 + distanceBetweenGroundPieces) * (-rowsIndex);
newGridPiece.transform.position = newPos;
newGridPiece.name = " piece_row_" + rowsIndex + " piece_col_" + columnsIndex;
rows[rowsIndex].gridPieces[columnsIndex] = newGridPiece;
columns[columnsIndex].gridPieces[rowsIndex] = newGridPiece;
gridPieces.Add(newGridPiece);
lastSpawnedRowPiece = newGridPiece.GetComponent<GridPiece>();
}
else if (rowsIndex == 5)
{
GridPiece newGridPiece = Instantiate(gridPiece.gameObject).GetComponent<GridPiece>();
newGridPiece.transform.SetParent(gridPiecesContainer.transform);
Vector3 newPos = newGridPiece.transform.position;
// GENERATING FROM TOP LEFT
newPos.x = (newGridPiece.GetWidth() / 2 + distanceBetweenGroundPieces) * columnsIndex;
newPos.y = (newGridPiece.GetHeight() / 2 + distanceBetweenGroundPieces) * (-rowsIndex);
newGridPiece.transform.position = newPos;
newGridPiece.name = " piece_row_" + rowsIndex + " piece_col_" + columnsIndex;
rows[rowsIndex].gridPieces[columnsIndex] = newGridPiece;
columns[columnsIndex].gridPieces[rowsIndex] = newGridPiece;
gridPieces.Add(newGridPiece);
lastSpawnedRowPiece = newGridPiece.GetComponent<GridPiece>();
}
else if ((columnsIndex >= 1 && columnsIndex <= 8) && rowsIndex == 6)
{
GridPiece newGridPiece = Instantiate(gridPiece.gameObject).GetComponent<GridPiece>();
newGridPiece.transform.SetParent(gridPiecesContainer.transform);
Vector3 newPos = newGridPiece.transform.position;
// GENERATING FROM TOP LEFT
newPos.x = (newGridPiece.GetWidth() / 2 + distanceBetweenGroundPieces) * columnsIndex;
newPos.y = (newGridPiece.GetHeight() / 2 + distanceBetweenGroundPieces) * (-rowsIndex);
newGridPiece.transform.position = newPos;
newGridPiece.name = " piece_row_" + rowsIndex + " piece_col_" + columnsIndex;
rows[rowsIndex].gridPieces[columnsIndex] = newGridPiece;
columns[columnsIndex].gridPieces[rowsIndex] = newGridPiece;
gridPieces.Add(newGridPiece);
lastSpawnedRowPiece = newGridPiece.GetComponent<GridPiece>();
}
else if ((columnsIndex >= 2 && columnsIndex <= 7) && rowsIndex == 7)
{
GridPiece newGridPiece = Instantiate(gridPiece.gameObject).GetComponent<GridPiece>();
newGridPiece.transform.SetParent(gridPiecesContainer.transform);
Vector3 newPos = newGridPiece.transform.position;
// GENERATING FROM TOP LEFT
newPos.x = (newGridPiece.GetWidth() / 2 + distanceBetweenGroundPieces) * columnsIndex;
newPos.y = (newGridPiece.GetHeight() / 2 + distanceBetweenGroundPieces) * (-rowsIndex);
newGridPiece.transform.position = newPos;
newGridPiece.name = " piece_row_" + rowsIndex + " piece_col_" + columnsIndex;
rows[rowsIndex].gridPieces[columnsIndex] = newGridPiece;
columns[columnsIndex].gridPieces[rowsIndex] = newGridPiece;
gridPieces.Add(newGridPiece);
lastSpawnedRowPiece = newGridPiece.GetComponent<GridPiece>();
}
else if ((columnsIndex >= 3 && columnsIndex <= 6) && rowsIndex == 8)
{
GridPiece newGridPiece = Instantiate(gridPiece.gameObject).GetComponent<GridPiece>();
newGridPiece.transform.SetParent(gridPiecesContainer.transform);
Vector3 newPos = newGridPiece.transform.position;
// GENERATING FROM TOP LEFT
newPos.x = (newGridPiece.GetWidth() / 2 + distanceBetweenGroundPieces) * columnsIndex;
newPos.y = (newGridPiece.GetHeight() / 2 + distanceBetweenGroundPieces) * (-rowsIndex);
newGridPiece.transform.position = newPos;
newGridPiece.name = " piece_row_" + rowsIndex + " piece_col_" + columnsIndex;
rows[rowsIndex].gridPieces[columnsIndex] = newGridPiece;
columns[columnsIndex].gridPieces[rowsIndex] = newGridPiece;
gridPieces.Add(newGridPiece);
lastSpawnedRowPiece = newGridPiece.GetComponent<GridPiece>();
}
else if ((columnsIndex >= 4 && columnsIndex <= 5) && rowsIndex == 9)
{
GridPiece newGridPiece = Instantiate(gridPiece.gameObject).GetComponent<GridPiece>();
newGridPiece.transform.SetParent(gridPiecesContainer.transform);
Vector3 newPos = newGridPiece.transform.position;
// GENERATING FROM TOP LEFT
newPos.x = (newGridPiece.GetWidth() / 2 + distanceBetweenGroundPieces) * columnsIndex;
newPos.y = (newGridPiece.GetHeight() / 2 + distanceBetweenGroundPieces) * (-rowsIndex);
newGridPiece.transform.position = newPos;
newGridPiece.name = " piece_row_" + rowsIndex + " piece_col_" + columnsIndex;
rows[rowsIndex].gridPieces[columnsIndex] = newGridPiece;
columns[columnsIndex].gridPieces[rowsIndex] = newGridPiece;
gridPieces.Add(newGridPiece);
lastSpawnedRowPiece = newGridPiece.GetComponent<GridPiece>();
}
}
}
public bool IsGameOver ()
{
bool gameOver = true;
foreach (Tetrimo tetrimo in TetrimoSpawner.instance.spawnedTetrimos) {
if (tetrimo != null) {
if (tetrimo.CanFitInGrid ()) {
gameOver = false;
break;
}
}
}
return gameOver;
}
public void CleanCompletedRowsAndColumns ()
{
List<GridPiecesSet> rowsAndColumnsToClean = new List<GridPiecesSet> ();
foreach (GridPiecesSet row in rows) {
if (row.AllPiecesFilled () && row.colorMatch()) {
rowsAndColumnsToClean.Add (row);
}
}
foreach (GridPiecesSet column in columns) {
if (column.AllPiecesFilled () && column.colorMatch()) {
rowsAndColumnsToClean.Add (column);
}
}
if (rowsAndColumnsToClean.Count > 0) {
ClearAllCompletedRowsAndColumns (rowsAndColumnsToClean);
}
}
public void ClearAllCompletedRowsAndColumns (List<GridPiecesSet> rowsAndColumnsToClean)
{
SoundsManager.instance.PlayLineCompleted ();
foreach (GridPiecesSet pieceSet in rowsAndColumnsToClean) {
pieceSet.Clean ();
StartCoroutine (DOCleanAnimation (pieceSet));
}
}
public void ClearGrid ()
{
foreach (GridPiece gridPiece in gridPieces) {
gridPiece.SetFilled (false);
}
}
public GridPieceConfiguration[] GetCurrentGridConfiguration ()
{
GridPieceConfiguration[] gridConfig = new GridPieceConfiguration[gridPieces.Count ()];
int count = 0;
foreach (GridPiece gridPiece in gridPieces) {
gridConfig [count] = new GridPieceConfiguration ();
gridConfig [count].ActivationState = gridPiece.isFilled;
gridConfig [count].TetrimoThatFillsName = gridPiece.tetrimoPieceThatFillsMeName;
count++;
}
return gridConfig;
}
public void TurnOffAllTutorialFillablePieces ()
{
foreach (GridPiece piece in gridPieces) {
piece.SetIlluminated (false);
piece.SetTutorialFillable (false);
}
}
public void SetGridByConfiguration (GridPieceConfiguration[] configs)
{
int count = 0;
foreach (GridPieceConfiguration config in configs) {
GridPiece iteratedPiece = gridPieces [count];
if (config.ActivationState == true) {
iteratedPiece.SetFilled (true);
Tetrimo tetrimoThatFillsGridPiece = Resources.Load<Tetrimo> ("Tetrimos/" + config.TetrimoThatFillsName);
if (tetrimoThatFillsGridPiece == null) {
throw new UnassignedReferenceException ();
}
iteratedPiece.SetTetrimoThatFillsMe (tetrimoThatFillsGridPiece);
} else {
iteratedPiece.SetFilled (false);
}
iteratedPiece.SetIlluminated (false);
iteratedPiece.SetTutorialFillable (true);
count++;
}
}
public IEnumerator DOCleanAnimation (GridPiecesSet piecesSet)
{
List<GridPiece> gridPiecesToAnimate = new List<GridPiece> ();
foreach (GridPiece piece in piecesSet.gridPieces) {
if (piece != null)
{
GridPiece clonePiece = GameObject.Instantiate(piece.gameObject).GetComponent<GridPiece>();
clonePiece.transform.position = piece.transform.position;
clonePiece.graphicWhenFilled.sortingOrder += 10;
clonePiece.SetFilled(true);
gridPiecesToAnimate.Add(clonePiece);
}
}
foreach (GridPiece piece in gridPiecesToAnimate) {
if (piece != null)
{
StartCoroutine(DisappearAnim(piece, piecesSet));
yield return new WaitForSeconds(0.07f);
}
}
yield return new WaitForEndOfFrame ();
}
IEnumerator DisappearAnim (GridPiece piece, GridPiecesSet piecesSet)
{
float t = 0;
float animTime = 0.15f;
Vector3 startScale = piece.transform.localScale;
Vector3 targetScale = Vector3.zero;
while (t <= 1) {
piece.transform.localScale = Vector3.Lerp (startScale, targetScale, t);
t += Time.deltaTime / animTime;
yield return new WaitForEndOfFrame ();
if (t >= 1) {
piece.transform.localScale = targetScale;
}
}
piece.DestroySelf ();
}
and finally the inputhandler that handles input from mouse or touch
bool isDragging = false;
Tetrimo tetrimoToMove = null;
// Use this for initialization
void Start ()
{
}
void Update ()
{
if (Input.GetMouseButtonDown (0)) {
OnMouseButtonDown ();
}
if (Input.GetMouseButtonUp (0)) {
OnMouseButtonUp ();
}
if (isDragging) {
OnDrag ();
}
}
public void OnDrag ()
{
tetrimoToMove.OnDrag ();
}
public void OnMouseButtonUp ()
{
if (isDragging) {
if (tetrimoToMove.CanBeReleasedOverGrid ()) {
Debug.Log("Mouse Up");
if (TutorialManager.instance.isShowingTutorial) {
StartCoroutine (TutorialManager.instance.OnTetrimoReleasedOverGrid ());
}
SoundsManager.instance.PlayTetrimoPlacement ();
tetrimoToMove.PlaceOverGrid ();
Grid.instance.CleanCompletedRowsAndColumns ();
if (Grid.instance.IsGameOver () && !TetrimoSpawner.instance.HasToSpawnNewTetrimos () && !TutorialManager.instance.isShowingTutorial) {
StartCoroutine(ObliusGameManager.instance.GameOver ());
Debug.Log ("GAME OVER");
} else {
Debug.Log ("GAME CAN CONTINUE");
}
if (!TutorialManager.instance.isShowingTutorial) {
GameStateSerializer.SaveCurrentState (Grid.instance, TetrimoSpawner.instance, ScoreHandler.instance);
}
if (!TutorialManager.instance.isShowingTutorial && TetrimoSpawner.instance.HasToSpawnNewTetrimos()) {
StartCoroutine (TetrimoSpawner.instance.TetrimoSpawnRoutine (true));
}
} else {
tetrimoToMove.StopDrag ();
tetrimoToMove.ReturnToSpawnPoint (0.1f);
}
}
isDragging = false;
}
public void OnMouseButtonDown ()
{
if (!isDragging && ObliusGameManager.instance.gameState != ObliusGameManager.GameState.gameover) {
tetrimoToMove = GetClickedTetrimo ();
if (tetrimoToMove != null) {
if (TutorialManager.instance.isShowingTutorial) {
if (tetrimoToMove.assignedSpawnPoint != TutorialManager.instance.currentShownTutorialStep.clickableSpawnPoint) {
isDragging = false;
return;
}
TutorialManager.instance.tutorialhand.StopMoveAndHide ();
}
isDragging = true;
} else {
isDragging = false;
}
}
}
public Tetrimo GetClickedTetrimo ()
{
Tetrimo clickedTetrimo = null;
Vector3 mousePos = Input.mousePosition;
mousePos.z = 10;
Vector3 screenPos = Camera.main.ScreenToWorldPoint (mousePos);
RaycastHit2D hit = Physics2D.Raycast (screenPos, Vector2.zero);
if (hit) {
Tetrimo hitTetrimo = hit.transform.GetComponentInParent<Tetrimo> ();
TetrimoSpawnPoint hitSpawnPoint = hit.transform.GetComponent<TetrimoSpawnPoint> ();
if (hitTetrimo != null) {
clickedTetrimo = hitTetrimo;
} else if (hitSpawnPoint != null) {
clickedTetrimo = hitSpawnPoint.assignedTetrimo;
Debug.Log ("Spawn point hit");
}
}
return clickedTetrimo;
}
Related
Lerp between point on LineRenderer
Im stuck on how to lerp between points of the linerenderer which are added on runtime. It should animate in order. So IEnumerator should be used i guess. private void makeLine(Transform finalPoint) { if(lastPoints == null) { lastPoints = finalPoint; points.Add(lastPoints); } else { points.Add(finalPoint); lr.enabled = true; SetupLine(); } } private void SetupLine() { int pointLength = points.Count; lr.positionCount = pointLength; for (int i = 0; i < pointLength; i++) { lr.SetPosition(i, points[i].position); // StartCoroutine(AnimateLine()); } } I found a code example. But now sure how to implement it so it would fit the code above: private IEnumerator AnimateLine() { //coroutinIsDone = false; float segmentDuration = animationDuration / points.Count; for (int i = 0; i < points.Count - 1; i++) { float startTime = Time.time; Vector3 startPosition = points[i].position; Vector3 endPosition = points[i + 1].position; Vector3 pos = startPosition; while (pos != endPosition) { float t = (Time.time - startTime) / segmentDuration; pos = Vector3.Lerp(startPosition, endPosition, t); for (int j = i + 1; j < points.Count; j++) lr.SetPosition(j, pos); yield return null; } } }
GetPixel makes the game slow
I'm creating a cleaning game but in the getpixel line of code makes the game slow or having a delay. I need this line of code to detect the remaining dirt. How can I improve the code? or is there other way to detect remaining dirt? private void Update() { if (Input.touchCount > 0) { Touch touch = Input.GetTouch(0); if (touch.phase == TouchPhase.Began) { if (touch.position != currentPosition || touch.position != prevPosition) { SetSinglePixel(touch.position); prevPosition = touch.position; } } else if (touch.phase == TouchPhase.Moved) { if (touch.position != currentPosition || touch.position != prevPosition) { currentPosition = touch.position; Vector2 dif = currentPosition - prevPosition; float distance = dif.magnitude; if (distance > 36) { float count = distance / 36; float n = distance / (count + 1); float ddmo = 36; for (int i = 0; i <= count; i++) { Vector2 gapPoint = Vector2.MoveTowards(prevPosition, currentPosition, ddmo * i); if (Physics.Raycast(Camera.main.ScreenPointToRay(gapPoint), out RaycastHit hit)) { gapPositions.Add(hit.textureCoord); } } SetMultiplePixel(gapPositions); gapPositions.Clear(); } else { SetSinglePixel(currentPosition); } prevPosition = touch.position; } } } } private void SetMultiplePixel(List<Vector2> givenPoints) { foreach (Vector2 pos in givenPoints) { SetPixel(pos.x, pos.y); } } private void SetSinglePixel(Vector2 touchPos) { if (Physics.Raycast(Camera.main.ScreenPointToRay(touchPos), out RaycastHit hit)) { SetPixel(hit.textureCoord.x, hit.textureCoord.y); } } public void ResetTexture() { SceneManager.LoadScene(SceneManager.GetActiveScene().name); } private void SetPixel(float textureCoordX, float textureCoordY, bool isCheckRemainingTexture = false) { int pixelX = (int)(textureCoordX * _templateDirtMask.width); int pixelY = (int)(textureCoordY * _templateDirtMask.height); int pixelXOffset = pixelX - (_brush.width / 2); int pixelYOffset = pixelY - (_brush.height / 2); for (int x = 0; x < _brush.width; x++) { for (int y = 0; y < _brush.height; y++) { data = (pixelXOffset + x) + (pixelYOffset + y) * _templateDirtMask.width; if (data > 0 && data < pixels.Length) { pixelDirt = _brush.GetPixel(x, y);// this code makes the game slow Color pixelDirtMask = _templateDirtMask.GetPixel(pixelXOffset + x, pixelYOffset + y); // this code makes the game slow float removedAmount = pixelDirtMask.g - (pixelDirtMask.g * pixelDirt.g); dirtAmount -= removedAmount; pixels[data] = new Color(0, pixelDirtMask.g * pixelDirt.g, 0); } } } ApplyTexture(); }
My playable character turns left or right when it meets an obstacle
My playable character turns left or right when it meets an obstacle with a collider. It's normal but I want to know if there is a way to disable it.
this is the script using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerMotor : MonoBehaviour { public Vector3 startPosition; private const float LANE_DISTANCE = 3.0f; private const float TURN_SPEED = 0.5f; //Functionality private bool isRunning = false; public bool isClimbing = false; private readonly object down; private CharacterController controller; [SerializeField] private float jumpForce = 5.0f; private float verticalVelocity = 0.0f; private float gravity = 10.0f; //Speed private float originalSpeed = 4.0f; private float speed = 4.0f; private float speedIncreaseLastTick; private float speedIncreaseTime = 2.5f; private float speedIncreaseAmount = 0.1f; private float climbingSpeed = 1.0f; private int desiredLane = 0; //0 = left, 1 = middle, 2 = right private Animator anim; // Start is called before the first frame update void Start() { speed = originalSpeed; controller = GetComponent<CharacterController>(); anim = GetComponent<Animator>(); transform.position = startPosition; } // Update is called once per frame void Update() { if (isClimbing) { transform.Translate(Vector3.up * climbingSpeed * Time.deltaTime); } if (!isRunning) return; if (Time.time - speedIncreaseLastTick > speedIncreaseTime) { speedIncreaseLastTick = Time.time; speed += speedIncreaseAmount; //GameManager.Instance.UpdateScores(); } // Gather the inputs on wich lane we should be if (MobileInput.Instance.SwipeLeft) { MoveLane(false); } if (MobileInput.Instance.SwipeRight) { MoveLane(true); } // Calculate where we should be horizontally Vector3 targetPosition = transform.position.z * Vector3.forward; int posX = Mathf.Abs(desiredLane); if (desiredLane < 0) targetPosition += Vector3.left * posX * LANE_DISTANCE; else if (desiredLane > 0) targetPosition += Vector3.right * posX * LANE_DISTANCE; //Calculate move delta Vector3 moveVector = Vector3.zero; moveVector.x = (targetPosition - transform.position).normalized.x * speed; bool isGrounded = IsGrounded(); anim.SetBool("Grounded", isGrounded); //Calculate y if (isGrounded) //If grounded { verticalVelocity = -0.1f; if (MobileInput.Instance.SwipeUp) { //Jump anim.SetTrigger("Jump"); verticalVelocity = jumpForce; } else if (MobileInput.Instance.SwipeDown) { //Slide StartSliding(); Invoke("StopSliding", 1.0f); } } else { verticalVelocity -= (gravity * Time.deltaTime); //Fast falling machanics if (MobileInput.Instance.SwipeDown) { verticalVelocity = -jumpForce; } } moveVector.y = verticalVelocity; moveVector.z = speed; //Move the character controller.Move(moveVector * Time.deltaTime); //Rotate the player where is going Vector3 dir = controller.velocity; if (dir!= Vector3.zero) { dir.y = 0; transform.forward = Vector3.Lerp(transform.forward, dir, TURN_SPEED); } } // This function (MoveLane) allows the player to move to the left and to the right private void MoveLane(bool goingRight) { if (!goingRight) { desiredLane--; if (desiredLane == -6) desiredLane = -5; } if (goingRight) { desiredLane++; if (desiredLane == 6) desiredLane = 5; } /* We wan rewrite the above function like this below desiredLane += (goingRight) ? 1 : -1; Mathf.Clamp(desiredLane, -5, 5); */ } private bool IsGrounded() { Ray groundRay = new Ray(new Vector3(controller.bounds.center.x, (controller.bounds.center.y - controller.bounds.extents.y) + 0.2f, controller.bounds.center.z), Vector3.down); Debug.DrawRay(groundRay.origin, groundRay.direction, Color.cyan, 1.0f); return (Physics.Raycast(groundRay, 0.2f + 0.1f)); } public void StartRunning () { isRunning = true; anim.SetTrigger("StartRunning"); } private void StartSliding() { anim.SetBool("Sliding", true); controller.height /= 2; controller.center = new Vector3(controller.center.x, controller.center.y / 2, controller.center.z); } private void StopSliding() { anim.SetBool("Sliding", false); controller.height *= 2; controller.center = new Vector3(controller.center.x, controller.center.y * 2, controller.center.z); } private void Crash() { anim.SetTrigger("Death"); isRunning = false; } private void OnControllerColliderHit(ControllerColliderHit hit) { switch(hit.gameObject.tag) { case "Obstacle": Crash(); break; } } private void OnTriggerEnter(Collider other) { if (other.gameObject.tag == "Ladder") { isRunning = false; isClimbing = true; anim.SetBool("ClimbingLadder", true); } else if (other.gameObject.tag == "LadderCol2") { isClimbing = false; anim.SetBool("ClimbingLadder", false); transform.Translate(Vector3.forward * 1); isRunning = true; } } }
I see the problem. It's from these lines Vector3 dir = controller.velocity; if (dir!= Vector3.zero) { dir.y = 0; transform.forward = Vector3.Lerp(transform.forward, dir, TURN_SPEED); } I added them to rotate a bit the player when it turns left or right.
How can I make my character move only forward in Unity?
I have a character in Unity which use a move script, to transform its position.x, y, or z everytime when I press the appropriate button. Now I would like to change my code to just rotate the character when the user press the "a" or "d" and don't move it, however if the user press the "w" button move it forward. I have already looked for it on the internet, and found out that I would need to use Vector3.forward somehow, but it doesn't work. Here is my script: This is the script which actually moves the character: (It is attached to a Player object which contains the moveable characters) public class Move : MonoBehaviour { float lerpTime; float currentLerpTime; float perc = 1; Vector3 startPos; Vector3 endPos; bool firstInput; public bool justJump; // Update is called once per frame void Update () { if (Input.GetButtonDown("up") || Input.GetButtonDown("down") || Input.GetButtonDown("left") || Input.GetButtonDown("right")) { if (perc == 1) { lerpTime = 1; currentLerpTime = 0; firstInput = true; justJump = true; } } startPos = gameObject.transform.position; if (Input.GetButtonDown("right") && gameObject.transform.position == endPos) { endPos = new Vector3(transform.position.x + 0.5f, transform.position.y, transform.position.z); } if (Input.GetButtonDown("left") && gameObject.transform.position == endPos) { endPos = new Vector3(transform.position.x - 0.5f, transform.position.y, transform.position.z); } if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) { endPos = new Vector3(transform.position.x, transform.position.y, transform.position.z + 0.5f); } if (Input.GetButtonDown("down") && gameObject.transform.position == endPos) { endPos = new Vector3(transform.position.x, transform.position.y, transform.position.z - 0.5f); } if (firstInput == true) { currentLerpTime += Time.deltaTime * 5; perc = currentLerpTime / lerpTime; gameObject.transform.position = Vector3.Lerp(startPos, endPos, perc); if (perc > 0.8f) { perc = 1; } if (Mathf.Round(perc) == 1) { justJump = false; } } } } And here is my "rotate script", which is attached to the moveable character(s) itself: public class AnimationController : MonoBehaviour { Animator anim; public GameObject thePlayer; // Use this for initialization void Start () { anim = gameObject.GetComponent<Animator>(); } // Update is called once per frame void Update () { Move moveScript = thePlayer.GetComponent<Move>(); if (moveScript.justJump == true) { anim.SetBool("Jump", true); } else { anim.SetBool("Jump", false); } if (Input.GetButtonDown("right")) { gameObject.transform.rotation = Quaternion.Euler(0, 90, 0); } if (Input.GetButtonDown("left")) { gameObject.transform.rotation = Quaternion.Euler(0, -90, 0); } if (Input.GetButtonDown("up")) { gameObject.transform.rotation = Quaternion.Euler(0, 0, 0); } if (Input.GetButtonDown("down")) { gameObject.transform.rotation = Quaternion.Euler(0, 180, 0); } } } Could you give me please any help on this? (Preferably with code, if you can :) )
Assuming you want your character to move to where it is facing, and trying not to do a lot of changes to your code, this is what could be done: First, attach both your script directly to your movable character. Then, change your Move script to: public class Move : MonoBehaviour { float lerpTime; float currentLerpTime; float perc = 1; Vector3 startPos; Vector3 endPos; bool firstInput; public bool justJump; // Update is called once per frame void Update () { if (Input.GetButtonDown("up") || Input.GetButtonDown("down") || Input.GetButtonDown("left") || Input.GetButtonDown("right")) { if (perc == 1) { lerpTime = 1; currentLerpTime = 0; firstInput = true; justJump = true; } } startPos = gameObject.transform.position; if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) { endPos = transform.position + gameObject.transform.rotation * (new Vector3(0, 0, 0.5f)); } if (Input.GetButtonDown("down") && gameObject.transform.position == endPos) { endPos = transform.position + gameObject.transform.rotation * (new Vector3(0, 0, 0.5f)); } if (firstInput == true) { currentLerpTime += Time.deltaTime * 5; perc = currentLerpTime / lerpTime; gameObject.transform.position = Vector3.Lerp(startPos, endPos, perc); if (perc > 0.8f) { perc = 1; } if (Mathf.Round(perc) == 1) { justJump = false; } } } } And your AnimationController script to public class AnimationController : MonoBehaviour { Animator anim; public GameObject thePlayer; // Use this for initialization void Start () { anim = gameObject.GetComponent<Animator>(); } // Update is called once per frame void Update () { Move moveScript = thePlayer.GetComponent<Move>(); if (moveScript.justJump == true) { anim.SetBool("Jump", true); } else { anim.SetBool("Jump", false); } if (Input.GetButtonDown("right")) { gameObject.transform.rotation = gameObject.transform.rotation * Quaternion.Euler(0, 90, 0); } if (Input.GetButtonDown("left")) { gameObject.transform.rotation = gameObject.transform.rotation * Quaternion.Euler(0, 90, 0); } } } This will make your character rotate only when you press the left and right buttons, and move only when you press the up and down button. Althought this solves your problem, this is not the best way to write scripts for your character movement. I recommend you read more about the state machine design patter. This book by Robert Nystrom has a chapter about it and is really easy to read. Also, its free to read online :)
Is there a custom Label widget which supports animated GIF?
I am trying to write a custom Label widget which supports animated GIF, but I found it's hard for me. Is there already such a widget available for use? Edit--------------------------------------------------------------------------------- When I try to use GifCLabel class, it works fine with a gif picture(animated), but if I try to set a static png picture to it when the animation thread is running, the png picture will not be shown, but a frame of the animated gif is shown, here is my code : public PageDemo(Shell parentShell) { super(parentShell); Composite topComp = new Composite(parentShell, SWT.NONE); topComp.setLayout(new FormLayout()); final GifCLabel gl = new GifCLabel(topComp, SWT.CENTER); gl.setText("some message"); gl.setGifImage("c://loading.gif"); Display.getCurrent().timerExec(5000, new Runnable(){ #Override public void run() { // gl.setGifImage("c:\\filter.png"); // also not work gl.setImage(SWTResourceManager.getImage("c:\\filter.png")); } }); } Bug fix-------------------------------------------------------------------------------- I think Sorceror's code is good, but there seems is a little bug: public void run() { while (run) { int delayTime = loader.data[imageNumber].delayTime; try { Thread.sleep(delayTime * 10); } catch (InterruptedException e) { e.printStackTrace(); } if (!GifCLabel.this.isDisposed()) { // if a asynchronous thread is running, this new runnable will be queued GifCLabel.this.getDisplay().asyncExec(new Runnable() { public void run() { if(!run){ return; } if (!GifCLabel.this.isDisposed()) { imageNumber = imageNumber == loader.data.length - 1 ? 0 : imageNumber + 1; if (!GifCLabel.this.image.isDisposed()) GifCLabel.this.image.dispose(); ImageData nextFrameData = loader.data[imageNumber]; System.out.println("set to frame " + imageNumber); GifCLabel.this.image = new Image(GifCLabel.this.getDisplay(), nextFrameData); GifCLabel.this.redraw(); } else stopRunning(); } }); } else stopRunning(); } } notice what I added in above : if(!run){ return; }
In the article Taking a look at SWT Images - Animation part is whole source code of gif animation for almost any purpose.. It didn't help? EDIT So I did the job, and here is a GifCLabel class for you which supports gif animation.. It's derived from SWT CLabel class, see setGifImage(String path), setGifImage(InputStream inputStream) methods and GifThread private class. import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.events.*; import org.eclipse.swt.accessibility.*; /** * <p><b>This class supports gif animation in label and is derived from {#link GifCLabel} SWT class (see {#link #setGifImage(InputStream)} or {#link #setGifImage(String)})</b><br /> * <b>Changes by Sorceror, (a)sync.exec(...) call fix by YAMaiDie</b></p> */ public class GifCLabel extends Canvas { /** Gap between icon and text */ private static final int GAP = 5; /** Left and right margins */ private static final int DEFAULT_MARGIN = 3; /** a string inserted in the middle of text that has been shortened */ private static final String ELLIPSIS = "..."; //$NON-NLS-1$ // could use the ellipsis glyph on some platforms "\u2026" /** the alignment. Either CENTER, RIGHT, LEFT. Default is LEFT*/ private int align = SWT.LEFT; private int leftMargin = DEFAULT_MARGIN; private int topMargin = DEFAULT_MARGIN; private int rightMargin = DEFAULT_MARGIN; private int bottomMargin = DEFAULT_MARGIN; private String text; private Image image; private String appToolTipText; private boolean ignoreDispose; private Image backgroundImage; private Color[] gradientColors; private int[] gradientPercents; private boolean gradientVertical; private Color background; private GifThread thread = null; private static int DRAW_FLAGS = SWT.DRAW_MNEMONIC | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT | SWT.DRAW_DELIMITER; public GifCLabel(Composite parent, int style) { super(parent, checkStyle(style)); if ((style & (SWT.CENTER | SWT.RIGHT)) == 0) style |= SWT.LEFT; if ((style & SWT.CENTER) != 0) align = SWT.CENTER; if ((style & SWT.RIGHT) != 0) align = SWT.RIGHT; if ((style & SWT.LEFT) != 0) align = SWT.LEFT; addPaintListener(new PaintListener() { public void paintControl(PaintEvent event) { onPaint(event); } }); addTraverseListener(new TraverseListener() { public void keyTraversed(TraverseEvent event) { if (event.detail == SWT.TRAVERSE_MNEMONIC) { onMnemonic(event); } } }); addListener(SWT.Dispose, new Listener() { public void handleEvent(Event event) { onDispose(event); } }); initAccessible(); } private static int checkStyle (int style) { if ((style & SWT.BORDER) != 0) style |= SWT.SHADOW_IN; int mask = SWT.SHADOW_IN | SWT.SHADOW_OUT | SWT.SHADOW_NONE | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; style = style & mask; return style |= SWT.NO_FOCUS | SWT.DOUBLE_BUFFERED; } public Point computeSize(int wHint, int hHint, boolean changed) { checkWidget(); Point e = getTotalSize(image, text); if (wHint == SWT.DEFAULT){ e.x += leftMargin + rightMargin; } else { e.x = wHint; } if (hHint == SWT.DEFAULT) { e.y += topMargin + bottomMargin; } else { e.y = hHint; } return e; } private void drawBevelRect(GC gc, int x, int y, int w, int h, Color topleft, Color bottomright) { gc.setForeground(bottomright); gc.drawLine(x+w, y, x+w, y+h); gc.drawLine(x, y+h, x+w, y+h); gc.setForeground(topleft); gc.drawLine(x, y, x+w-1, y); gc.drawLine(x, y, x, y+h-1); } char _findMnemonic (String string) { if (string == null) return '\0'; int index = 0; int length = string.length (); do { while (index < length && string.charAt (index) != '&') index++; if (++index >= length) return '\0'; if (string.charAt (index) != '&') return Character.toLowerCase (string.charAt (index)); index++; } while (index < length); return '\0'; } public int getAlignment() { //checkWidget(); return align; } public int getBottomMargin() { //checkWidget(); return bottomMargin; } public Image getImage() { //checkWidget(); return image; } public int getLeftMargin() { //checkWidget(); return leftMargin; } public int getRightMargin() { //checkWidget(); return rightMargin; } private Point getTotalSize(Image image, String text) { Point size = new Point(0, 0); if (image != null) { Rectangle r = image.getBounds(); size.x += r.width; size.y += r.height; } GC gc = new GC(this); if (text != null && text.length() > 0) { Point e = gc.textExtent(text, DRAW_FLAGS); size.x += e.x; size.y = Math.max(size.y, e.y); if (image != null) size.x += GAP; } else { size.y = Math.max(size.y, gc.getFontMetrics().getHeight()); } gc.dispose(); return size; } public int getStyle () { int style = super.getStyle(); switch (align) { case SWT.RIGHT: style |= SWT.RIGHT; break; case SWT.CENTER: style |= SWT.CENTER; break; case SWT.LEFT: style |= SWT.LEFT; break; } return style; } public String getText() { //checkWidget(); return text; } public String getToolTipText () { checkWidget(); return appToolTipText; } public int getTopMargin() { //checkWidget(); return topMargin; } private void initAccessible() { Accessible accessible = getAccessible(); accessible.addAccessibleListener(new AccessibleAdapter() { public void getName(AccessibleEvent e) { e.result = getText(); } public void getHelp(AccessibleEvent e) { e.result = getToolTipText(); } public void getKeyboardShortcut(AccessibleEvent e) { char mnemonic = _findMnemonic(GifCLabel.this.text); if (mnemonic != '\0') { e.result = "Alt+"+mnemonic; //$NON-NLS-1$ } } }); accessible.addAccessibleControlListener(new AccessibleControlAdapter() { public void getChildAtPoint(AccessibleControlEvent e) { e.childID = ACC.CHILDID_SELF; } public void getLocation(AccessibleControlEvent e) { Rectangle rect = getDisplay().map(getParent(), null, getBounds()); e.x = rect.x; e.y = rect.y; e.width = rect.width; e.height = rect.height; } public void getChildCount(AccessibleControlEvent e) { e.detail = 0; } public void getRole(AccessibleControlEvent e) { e.detail = ACC.ROLE_LABEL; } public void getState(AccessibleControlEvent e) { e.detail = ACC.STATE_READONLY; } }); } void onDispose(Event event) { /* make this handler run after other dispose listeners */ if (ignoreDispose) { ignoreDispose = false; return; } ignoreDispose = true; notifyListeners (event.type, event); event.type = SWT.NONE; gradientColors = null; gradientPercents = null; backgroundImage = null; text = null; image = null; appToolTipText = null; } void onMnemonic(TraverseEvent event) { char mnemonic = _findMnemonic(text); if (mnemonic == '\0') return; if (Character.toLowerCase(event.character) != mnemonic) return; Composite control = this.getParent(); while (control != null) { Control [] children = control.getChildren(); int index = 0; while (index < children.length) { if (children [index] == this) break; index++; } index++; if (index < children.length) { if (children [index].setFocus ()) { event.doit = true; event.detail = SWT.TRAVERSE_NONE; } } control = control.getParent(); } } void onPaint(PaintEvent event) { Rectangle rect = getClientArea(); if (rect.width == 0 || rect.height == 0) return; boolean shortenText = false; String t = text; Image img = image; int availableWidth = Math.max(0, rect.width - (leftMargin + rightMargin)); Point extent = getTotalSize(img, t); if (extent.x > availableWidth) { img = null; extent = getTotalSize(img, t); if (extent.x > availableWidth) { shortenText = true; } } GC gc = event.gc; String[] lines = text == null ? null : splitString(text); // shorten the text if (shortenText) { extent.x = 0; for(int i = 0; i < lines.length; i++) { Point e = gc.textExtent(lines[i], DRAW_FLAGS); if (e.x > availableWidth) { lines[i] = shortenText(gc, lines[i], availableWidth); extent.x = Math.max(extent.x, getTotalSize(null, lines[i]).x); } else { extent.x = Math.max(extent.x, e.x); } } if (appToolTipText == null) { super.setToolTipText(text); } } else { super.setToolTipText(appToolTipText); } // determine horizontal position int x = rect.x + leftMargin; if (align == SWT.CENTER) { x = (rect.width - extent.x)/2; } if (align == SWT.RIGHT) { x = rect.width - rightMargin - extent.x; } // draw a background image behind the text try { if (backgroundImage != null) { // draw a background image behind the text Rectangle imageRect = backgroundImage.getBounds(); // tile image to fill space gc.setBackground(getBackground()); gc.fillRectangle(rect); int xPos = 0; while (xPos < rect.width) { int yPos = 0; while (yPos < rect.height) { gc.drawImage(backgroundImage, xPos, yPos); yPos += imageRect.height; } xPos += imageRect.width; } } else if (gradientColors != null) { // draw a gradient behind the text final Color oldBackground = gc.getBackground(); if (gradientColors.length == 1) { if (gradientColors[0] != null) gc.setBackground(gradientColors[0]); gc.fillRectangle(0, 0, rect.width, rect.height); } else { final Color oldForeground = gc.getForeground(); Color lastColor = gradientColors[0]; if (lastColor == null) lastColor = oldBackground; int pos = 0; for (int i = 0; i < gradientPercents.length; ++i) { gc.setForeground(lastColor); lastColor = gradientColors[i + 1]; if (lastColor == null) lastColor = oldBackground; gc.setBackground(lastColor); if (gradientVertical) { final int gradientHeight = (gradientPercents[i] * rect.height / 100) - pos; gc.fillGradientRectangle(0, pos, rect.width, gradientHeight, true); pos += gradientHeight; } else { final int gradientWidth = (gradientPercents[i] * rect.width / 100) - pos; gc.fillGradientRectangle(pos, 0, gradientWidth, rect.height, false); pos += gradientWidth; } } if (gradientVertical && pos < rect.height) { gc.setBackground(getBackground()); gc.fillRectangle(0, pos, rect.width, rect.height - pos); } if (!gradientVertical && pos < rect.width) { gc.setBackground(getBackground()); gc.fillRectangle(pos, 0, rect.width - pos, rect.height); } gc.setForeground(oldForeground); } gc.setBackground(oldBackground); } else { if (background != null || (getStyle() & SWT.DOUBLE_BUFFERED) == 0) { gc.setBackground(getBackground()); gc.fillRectangle(rect); } } } catch (SWTException e) { if ((getStyle() & SWT.DOUBLE_BUFFERED) == 0) { gc.setBackground(getBackground()); gc.fillRectangle(rect); } } // draw border int style = getStyle(); if ((style & SWT.SHADOW_IN) != 0 || (style & SWT.SHADOW_OUT) != 0) { paintBorder(gc, rect); } Rectangle imageRect = null; int lineHeight = 0, textHeight = 0, imageHeight = 0; if (img != null) { imageRect = img.getBounds(); imageHeight = imageRect.height; } if (lines != null) { lineHeight = gc.getFontMetrics().getHeight(); textHeight = lines.length * lineHeight; } int imageY = 0, midPoint = 0, lineY = 0; if (imageHeight > textHeight ) { if (topMargin == DEFAULT_MARGIN && bottomMargin == DEFAULT_MARGIN) imageY = rect.y + (rect.height - imageHeight) / 2; else imageY = topMargin; midPoint = imageY + imageHeight/2; lineY = midPoint - textHeight / 2; } else { if (topMargin == DEFAULT_MARGIN && bottomMargin == DEFAULT_MARGIN) lineY = rect.y + (rect.height - textHeight) / 2; else lineY = topMargin; midPoint = lineY + textHeight/2; imageY = midPoint - imageHeight / 2; } // draw the image if (img != null) { gc.drawImage(img, 0, 0, imageRect.width, imageHeight, x, imageY, imageRect.width, imageHeight); x += imageRect.width + GAP; extent.x -= imageRect.width + GAP; } // draw the text if (lines != null) { gc.setForeground(getForeground()); for (int i = 0; i < lines.length; i++) { int lineX = x; if (lines.length > 1) { if (align == SWT.CENTER) { int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x; lineX = x + Math.max(0, (extent.x - lineWidth) / 2); } if (align == SWT.RIGHT) { int lineWidth = gc.textExtent(lines[i], DRAW_FLAGS).x; lineX = Math.max(x, rect.x + rect.width - rightMargin - lineWidth); } } gc.drawText(lines[i], lineX, lineY, DRAW_FLAGS); lineY += lineHeight; } } } private void paintBorder(GC gc, Rectangle r) { Display disp= getDisplay(); Color c1 = null; Color c2 = null; int style = getStyle(); if ((style & SWT.SHADOW_IN) != 0) { c1 = disp.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); c2 = disp.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW); } if ((style & SWT.SHADOW_OUT) != 0) { c1 = disp.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW); c2 = disp.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); } if (c1 != null && c2 != null) { gc.setLineWidth(1); drawBevelRect(gc, r.x, r.y, r.width-1, r.height-1, c1, c2); } } public void setAlignment(int align) { checkWidget(); if (align != SWT.LEFT && align != SWT.RIGHT && align != SWT.CENTER) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } if (this.align != align) { this.align = align; redraw(); } } public void setBackground (Color color) { super.setBackground (color); // Are these settings the same as before? if (backgroundImage == null && gradientColors == null && gradientPercents == null) { if (color == null) { if (background == null) return; } else { if (color.equals(background)) return; } } background = color; backgroundImage = null; gradientColors = null; gradientPercents = null; redraw (); } public void setBackground(Color[] colors, int[] percents) { setBackground(colors, percents, false); } public void setBackground(Color[] colors, int[] percents, boolean vertical) { checkWidget(); if (colors != null) { if (percents == null || percents.length != colors.length - 1) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } if (getDisplay().getDepth() < 15) { // Don't use gradients on low color displays colors = new Color[] {colors[colors.length - 1]}; percents = new int[] { }; } for (int i = 0; i < percents.length; i++) { if (percents[i] < 0 || percents[i] > 100) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } if (i > 0 && percents[i] < percents[i-1]) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } } } // Are these settings the same as before? final Color background = getBackground(); if (backgroundImage == null) { if ((gradientColors != null) && (colors != null) && (gradientColors.length == colors.length)) { boolean same = false; for (int i = 0; i < gradientColors.length; i++) { same = (gradientColors[i] == colors[i]) || ((gradientColors[i] == null) && (colors[i] == background)) || ((gradientColors[i] == background) && (colors[i] == null)); if (!same) break; } if (same) { for (int i = 0; i < gradientPercents.length; i++) { same = gradientPercents[i] == percents[i]; if (!same) break; } } if (same && this.gradientVertical == vertical) return; } } else { backgroundImage = null; } // Store the new settings if (colors == null) { gradientColors = null; gradientPercents = null; gradientVertical = false; } else { gradientColors = new Color[colors.length]; for (int i = 0; i < colors.length; ++i) gradientColors[i] = (colors[i] != null) ? colors[i] : background; gradientPercents = new int[percents.length]; for (int i = 0; i < percents.length; ++i) gradientPercents[i] = percents[i]; gradientVertical = vertical; } // Refresh with the new settings redraw(); } public void setBackground(Image image) { checkWidget(); if (image == backgroundImage) return; if (image != null) { gradientColors = null; gradientPercents = null; } backgroundImage = image; redraw(); } public void setBottomMargin(int bottomMargin) { checkWidget(); if (this.bottomMargin == bottomMargin || bottomMargin < 0) return; this.bottomMargin = bottomMargin; redraw(); } public void setFont(Font font) { super.setFont(font); redraw(); } public void setImage(Image image) { checkWidget(); if(thread != null) { thread.stopRunning(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } if (image != this.image) { this.image = image; redraw(); } } public void setGifImage(String path) { try { this.setGifImage(new FileInputStream(new File(path))); } catch (FileNotFoundException e) { this.image = null; return; } } public void setGifImage(InputStream inputStream) { checkWidget(); if(thread != null) thread.stopRunning(); ImageLoader loader = new ImageLoader(); try { loader.load(inputStream); } catch (Exception e) { this.image = null; return; } if (loader.data[0] != null) this.image = new Image(this.getDisplay(), loader.data[0]); if (loader.data.length > 1) { thread = new GifThread(loader); thread.start(); } redraw(); } #Override public void dispose() { super.dispose(); if(thread != null) thread.stopRunning(); } private class GifThread extends Thread { private int imageNumber = 0; private ImageLoader loader = null; private boolean run = true; public GifThread(ImageLoader loader) { this.loader = loader; } public void run() { while(run) { int delayTime = loader.data[imageNumber].delayTime; try { Thread.sleep(delayTime * 10); } catch (InterruptedException e) { e.printStackTrace(); } if(!GifCLabel.this.isDisposed()) { GifCLabel.this.getDisplay().asyncExec(new Runnable() { public void run() { if(!run){ return; } if(!GifCLabel.this.isDisposed()) { imageNumber = imageNumber == loader.data.length - 1 ? 0 : imageNumber + 1; if (!GifCLabel.this.image.isDisposed()) GifCLabel.this.image.dispose(); ImageData nextFrameData = loader.data[imageNumber]; GifCLabel.this.image = new Image(GifCLabel.this.getDisplay(), nextFrameData); GifCLabel.this.redraw(); } else stopRunning(); } }); } else stopRunning(); } } public void stopRunning() { run = false; } } public void setLeftMargin(int leftMargin) { checkWidget(); if (this.leftMargin == leftMargin || leftMargin < 0) return; this.leftMargin = leftMargin; redraw(); } public void setMargins (int leftMargin, int topMargin, int rightMargin, int bottomMargin) { checkWidget(); this.leftMargin = Math.max(0, leftMargin); this.topMargin = Math.max(0, topMargin); this.rightMargin = Math.max(0, rightMargin); this.bottomMargin = Math.max(0, bottomMargin); redraw(); } public void setRightMargin(int rightMargin) { checkWidget(); if (this.rightMargin == rightMargin || rightMargin < 0) return; this.rightMargin = rightMargin; redraw(); } public void setText(String text) { checkWidget(); if (text == null) text = ""; //$NON-NLS-1$ if (! text.equals(this.text)) { this.text = text; redraw(); } } public void setToolTipText (String string) { super.setToolTipText (string); appToolTipText = super.getToolTipText(); } public void setTopMargin(int topMargin) { checkWidget(); if (this.topMargin == topMargin || topMargin < 0) return; this.topMargin = topMargin; redraw(); } protected String shortenText(GC gc, String t, int width) { if (t == null) return null; int w = gc.textExtent(ELLIPSIS, DRAW_FLAGS).x; if (width<=w) return t; int l = t.length(); int max = l/2; int min = 0; int mid = (max+min)/2 - 1; if (mid <= 0) return t; TextLayout layout = new TextLayout (getDisplay()); layout.setText(t); mid = validateOffset(layout, mid); while (min < mid && mid < max) { String s1 = t.substring(0, mid); String s2 = t.substring(validateOffset(layout, l-mid), l); int l1 = gc.textExtent(s1, DRAW_FLAGS).x; int l2 = gc.textExtent(s2, DRAW_FLAGS).x; if (l1+w+l2 > width) { max = mid; mid = validateOffset(layout, (max+min)/2); } else if (l1+w+l2 < width) { min = mid; mid = validateOffset(layout, (max+min)/2); } else { min = max; } } String result = mid == 0 ? t : t.substring(0, mid) + ELLIPSIS + t.substring(validateOffset(layout, l-mid), l); layout.dispose(); return result; } int validateOffset(TextLayout layout, int offset) { int nextOffset = layout.getNextOffset(offset, SWT.MOVEMENT_CLUSTER); if (nextOffset != offset) return layout.getPreviousOffset(nextOffset, SWT.MOVEMENT_CLUSTER); return offset; } private String[] splitString(String text) { String[] lines = new String[1]; int start = 0, pos; do { pos = text.indexOf('\n', start); if (pos == -1) { lines[lines.length - 1] = text.substring(start); } else { boolean crlf = (pos > 0) && (text.charAt(pos - 1) == '\r'); lines[lines.length - 1] = text.substring(start, pos - (crlf ? 1 : 0)); start = pos + 1; String[] newLines = new String[lines.length+1]; System.arraycopy(lines, 0, newLines, 0, lines.length); lines = newLines; } } while (pos != -1); return lines; } } and the possible usage is final GifCLabel lbl = new GifCLabel(shell, SWT.CENTER); lbl.setText("texxxxt"); lbl.setGifImage(this.getClass().getResourceAsStream("/8EWoM.gif")); // lbl.setGifImage("src/8EWoM.gif"); Because of the limit of 30000 chars to answer, the pasted code is without comments, non-trim version could be found on http://pastebin.com/cJA682XD